package client

import (
	"errors"
	"fastdp-ops/pkg/server/api"
	. "fastdp-ops/pkg/server/api/middleware"
	"fastdp-ops/pkg/server/api/models"
	. "fastdp-ops/pkg/server/config"
	gc "fastdp-ops/pkg/server/grpc"
	copypb "fastdp-ops/proto/copy"
	pb "fastdp-ops/proto/machine"
	"fmt"
	"github.com/gin-contrib/zap"
	"github.com/gin-gonic/gin"
	"github.com/sevlyar/go-daemon"
	"github.com/spf13/cobra"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"net"
	"os"
	"path/filepath"
	"time"
)

const pidFile = "fastdp-ops.pid"

// runCmd 启动服务命令
var RunCmd = &cobra.Command{
	Use:     "run",
	Short:   "启动fastdp-ops的web服务",
	Example: `  启动服务: fastdp-ops run --ip 192.168.1.1`,
	Args:    cobra.NoArgs, // 不接受位置参数
	PreRunE: func(cmd *cobra.Command, args []string) error {
		// 验证IP参数
		ip, _ := cmd.Flags().GetString("ip")
		if ip == "" {
			return errors.New("必须使用 -i/--ip 指定绑定的本机IP地址")
		}
		if !isLocalIP(ip) {
			return fmt.Errorf("指定的IP %s 不是本机已启用的IP地址", ip)
		}
		return nil
	},
	Run: func(cmd *cobra.Command, args []string) {
		ip, _ := cmd.Flags().GetString("ip")

		// 准备后台运行上下文
		if err := os.MkdirAll(filepath.Dir("logs/fastdp-ops.log"), 0755); err != nil {
			fmt.Printf("创建日志目录失败: %v\n", err)
			os.Exit(1)
		}

		ctx := &daemon.Context{
			PidFileName: pidFile,
			PidFilePerm: 0644,
			LogFileName: "logs/fastdp-ops.log",
			LogFilePerm: 0644,
			WorkDir:     "./",
			Umask:       027,
			// 给子进程设置环境变量，标记为后台进程
			Env: append(os.Environ(), "DAEMON=1"),
		}

		d, err := ctx.Reborn()
		if err != nil {
			fmt.Printf("启动后台进程失败: %v\n", err)
			os.Exit(1)
		}

		// 父进程逻辑
		if d != nil {
			url, fastdpCmd := InstallAgent(ip)
			fmt.Println("在需要纳管的agent节点执行：", url)
			fmt.Println(fastdpCmd)
			fmt.Printf("服务已后台启动，PID: %d，绑定IP: %s\n", d.Pid, ip)
			os.Exit(0)
			return
		}
		defer ctx.Release()

		// 子进程：启动服务逻辑
		startServices(ip)
	},
}

func init() {
	// run命令标志
	RunCmd.Flags().StringP("ip", "i", "", "服务绑定的本机IP地址（必需）")
	_ = RunCmd.MarkFlagRequired("ip") // 标记IP为必需参数
}

// isLocalIP 检查IP是否为本机已启用的网络地址（包括IPv4和IPv6）
func isLocalIP(ipStr string) bool {
	// 解析输入的IP地址
	targetIP := net.ParseIP(ipStr)
	if targetIP == nil {
		return false // 无效IP格式
	}

	// 获取本机所有网络接口的地址
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return false
	}

	// 遍历所有地址，检查是否匹配
	for _, addr := range addrs {
		// 解析接口地址（如 "192.168.1.101/24"）
		ipNet, ok := addr.(*net.IPNet)
		if !ok {
			continue
		}

		// 比较IP（忽略子网掩码）
		if ipNet.IP.Equal(targetIP) {
			return true
		}
	}

	return false
}

// 安装agent相关命令生成
func InstallAgent(bindIP string) (string, string) {
	port := V.GetString("fastdp-ops.port")
	url := fmt.Sprintf("curl -fSL http://%s:%s/static/fastdp-agent.sh | bash -x -s %s %s",
		bindIP, port, bindIP, port)
	fastdpCmd := fmt.Sprintf("如果已安装fastdp工具，可使用：fastdp shell -a '%s' all 快速安装agent", url)
	return url, fastdpCmd
}
func updateConfigListen(bindIP string) error {
	// 1. 从Viper获取当前配置的listen值
	currentListen := V.GetString("fastdp-ops.listen")

	// 2. 若已为目标值，无需修改
	if currentListen == bindIP {
		return nil
	}
	// 3. 更新Viper中的配置值
	V.Set("fastdp-ops.listen", bindIP)

	// 4. 写入配置文件（使用Viper自动管理路径和格式）
	// 注意：Viper会根据加载时的配置文件路径写入，需确保已正确加载配置
	err := V.WriteConfig()
	if err != nil {
		// 处理特殊情况：如果配置文件不存在（理论上不会，因为已用Viper读取过）
		if os.IsNotExist(err) {
			return fmt.Errorf("配置文件不存在，无法写入: %w", err)
		}
		return fmt.Errorf("写入配置文件失败: %w", err)
	}

	return nil
}

// 启动服务（子进程执行）
func startServices(bindIP string) {
	// 初始化配置和日志
	InitZapLogger()
	defer Logger.Sync()

	// 初始化数据库
	SqlLiteInit()
	_ = DB.AutoMigrate(&models.Machines{})

	// 启动gRPC服务
	grpcPort := ":" + V.GetString("fastdp-rpcserver.port")
	lis, err := net.Listen("tcp", grpcPort)
	if err != nil {
		Logger.Fatal("gRPC监听失败", zap.String("port", grpcPort), zap.Error(err))
	}

	grpcServer := grpc.NewServer()
	pb.RegisterMachineEnvServiceServer(grpcServer, &gc.Server{})
	copypb.RegisterFileTransferServiceServer(grpcServer, &gc.CopyServer{})
	Logger.Info("gRPC 服务启动成功", zap.String("listen_port", grpcPort))

	go func() {
		if err := grpcServer.Serve(lis); err != nil {
			Logger.Fatal("gRPC 服务崩溃", zap.Error(err))
		}
	}()

	// 启动Gin服务
	addr := fmt.Sprintf("%s:%s", bindIP, V.GetString("fastdp-ops.port"))
	router := gin.New()
	router.Use(
		ginzap.Ginzap(Logger, time.RFC3339, true),
		ginzap.RecoveryWithZap(Logger, true),
	)
	api.RouteInit(router)

	Logger.Info("Gin服务启动成功", zap.String("addr", addr))
	// 启动成功后修改配置文件
	if err := updateConfigListen(bindIP); err != nil {
		Logger.Warn("配置文件更新失败", zap.Error(err))
	} else {
		Logger.Info("配置文件更新成功", zap.String("new_listen", bindIP))
	}
	if err := router.Run(addr); err != nil {
		Logger.Fatal("Gin服务启动失败", zap.Error(err))
	}

}
